﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace ClientOperationContractGenerater
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            txtNamespace.Text = Properties.Settings.Default.Namespace;
            txtServiceName.Text = Properties.Settings.Default.ServiceName;
        }

        private void btnGenerate_Click(object sender, EventArgs e)
        {
            GenerateMulti(txtName.Text);
        }

        private void GenerateSingle(string operationName, out string classString, out string interfaceString) 
        {
            if (string.IsNullOrEmpty(operationName))
            {
                classString = null;
                interfaceString = null;
                return;
            }
            //
            int index = operationName.IndexOf(')');
            operationName = operationName.Substring(0, index).Trim();
            //
            index = operationName.IndexOf(' ');
            string feedback = operationName.Substring(0, index);
            operationName = operationName.Substring(index + 1).Trim();
            string eventArgs = string.Empty;
            if (feedback.Equals("Feedback"))
            {
                eventArgs = "FeedbackCompletedEventArgs";
            }
            else
            {
                int itemp = feedback.IndexOf("<");
                eventArgs = feedback.Insert(itemp, "CompletedEventArgs");
            }
            //
            index = operationName.IndexOf('(');
            string name = operationName.Substring(0, index);
            operationName = operationName.Substring(index + 1).Trim();
            // 
            string paramList = operationName;
            string paramListWithComma = operationName + ",";
            string parameterNames = string.Empty;
            string parameterNamesWithComma = string.Empty;
            string args = StaticData.ArgsBase;
            string paramInits = string.Empty;
            if (operationName.Length > 0)
            {
                index = operationName.IndexOf(',');
                int count = 0;
                string ntemp = string.Empty;
                string datatype = string.Empty;

                while (index != -1)
                {
                    string temp = operationName.Substring(0, index);
                    int itemp = operationName.IndexOf(' ');
                    ntemp = temp.Substring(itemp + 1);
                    datatype = temp.Substring(0, itemp);
                    parameterNames += ntemp.Trim();
                    parameterNames += ", ";

                    paramInits += StaticData.ParamInit.Replace(StaticData.DataType, datatype)
                                                      .Replace(StaticData.ParamName, ntemp)
                                                      .Replace(StaticData.ParamIndex, count.ToString());

                    args += StaticData.ArgsAssign.Replace(StaticData.ParamIndex, count.ToString())
                                               .Replace(StaticData.ParamName, ntemp);

                    operationName = operationName.Substring(index + 1).Trim();
                    index = operationName.IndexOf(',');
                    ++count;
                }
                index = operationName.IndexOf(' ');
                ntemp = operationName.Substring(index + 1);
                datatype = operationName.Substring(0, index);
                parameterNames += ntemp.Trim();
                parameterNamesWithComma = parameterNames + ",";
                
                paramInits += StaticData.ParamInit.Replace(StaticData.DataType, datatype)
                                                  .Replace(StaticData.ParamName, ntemp)
                                                  .Replace(StaticData.ParamIndex, count.ToString());

                args += StaticData.ArgsAssign.Replace(StaticData.ParamIndex, count.ToString())
                                           .Replace(StaticData.ParamName, ntemp);

                ++count;

                args = args.Replace(StaticData.NumberOfParams, count.ToString());
            }
            else
            {
                args = args.Replace(StaticData.NumberOfParams, "0");
                paramListWithComma = string.Empty;
            }

            classString = StaticData.ClassScript.Replace(StaticData.OperationContractName, name)
                .Replace(StaticData.Feedback, feedback)
                .Replace(StaticData.EventArgs, eventArgs)
                .Replace(StaticData.ParamsWithComma, paramListWithComma)
                .Replace(StaticData.Params, paramList)
                .Replace(StaticData.ParamNamesWithComma, parameterNamesWithComma)
                .Replace(StaticData.ParamNames, parameterNames)
                .Replace(StaticData.ParamInits, paramInits)
                .Replace(StaticData.Args, args)
                .Replace(StaticData.ServiceName, Properties.Settings.Default.ServiceName)
                .Replace(StaticData.Namespace, Properties.Settings.Default.Namespace);
            
            interfaceString = StaticData.InterfaceScript.Replace(StaticData.OperationContractName, name)
                .Replace(StaticData.Feedback, feedback)
                .Replace(StaticData.ParamsWithComma, paramListWithComma)
                .Replace(StaticData.ServiceName, Properties.Settings.Default.ServiceName)
                .Replace(StaticData.Namespace, Properties.Settings.Default.Namespace);
        }

        private void GenerateMulti(string operationNames)
        {
            if (string.IsNullOrEmpty(operationNames))
                return;

            txtClassScript.Text = string.Empty;
            txtInterfaceScript.Text = string.Empty;

            string[] operationNameCollection = operationNames.Split(new[] {"/n"}, StringSplitOptions.RemoveEmptyEntries);
            
            classBuilder = new StringBuilder(string.Empty);
            interfaceBuilder = new StringBuilder(string.Empty);

            foreach (string operationName in operationNameCollection)
            {
                string classString = string.Empty;
                string interfaceString = string.Empty;
                GenerateSingle(operationName, out classString, out interfaceString);
                classBuilder.Append(classString);
                interfaceBuilder.Append(interfaceString);
            }
            MessageBox.Show("Generate from operation declaration list", "Generating is completed.");
            txtClassScript.Text = classBuilder.ToString();
            txtInterfaceScript.Text = interfaceBuilder.ToString();
        }


        private void btnSave_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtServiceName.Text))
            {
                txtServiceName.Text = Properties.Settings.Default.ServiceName;
            }
            else
            {
                Properties.Settings.Default.ServiceName = txtServiceName.Text;
                Properties.Settings.Default.Save();
            }

            if (string.IsNullOrEmpty(txtServiceName.Text))
            {
                txtNamespace.Text = Properties.Settings.Default.Namespace;
            }
            else
            {
                Properties.Settings.Default.Namespace = txtNamespace.Text;
                Properties.Settings.Default.Save();
            }

            MessageBox.Show("Static Data", "New service name and namespace are saved.");
        }

        private StringBuilder interfaceBuilder;
        private StringBuilder classBuilder;

        private void btnGenerateFromFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "C# source | *.cs";

            DialogResult result = openFileDialog.ShowDialog(this);

            if (result==DialogResult.OK)
            {
                StreamReader reader = new StreamReader(openFileDialog.OpenFile());
                Stack<string> regionCollection = new Stack<string>();
                StringBuilder classResult = new StringBuilder(string.Empty);
                StringBuilder interfaceResult = new StringBuilder(string.Empty);
                string classDeclaration = StaticData.ClassDeclaration.Replace(StaticData.ServiceName,
                                                                              Properties.Settings.Default.ServiceName);
                while(!reader.EndOfStream)
                {
                    string tline = reader.ReadLine();
                    if (tline.IndexOf(StaticData.RegionMark)!=-1)
                    {
                        regionCollection.Push(tline.Replace(StaticData.RegionMark, string.Empty).Replace(" ", string.Empty));
                        classResult.Append(classDeclaration);
                        interfaceResult.Append(tline);
                        interfaceResult.AppendLine();

                    }
                    else if (tline.IndexOf(StaticData.OperationContractMark)!=-1)
                    {
                        tline = reader.ReadLine();
                        string classString = string.Empty;
                        string interfaceString = string.Empty;
                        GenerateSingle(tline, out classString, out interfaceString);
                        classResult.Append(classString);
                        interfaceResult.Append(interfaceString);
                    }
                    else if (tline.IndexOf(StaticData.EndregionMark) != -1)
                    {
                        classResult.Append(StaticData.CloseBrace);
                        interfaceResult.AppendLine();
                        interfaceResult.Append(tline);
                        interfaceResult.AppendLine();
                        interfaceResult.AppendLine();

                        string currentRegion = regionCollection.Pop();
                        string fileName = StaticData.ClassRegionFileNameTemplate
                                                    .Replace(StaticData.ServiceName, Properties.Settings.Default.ServiceName)
                                                    .Replace(StaticData.Region, currentRegion);
                        StreamWriter writer = new StreamWriter(fileName, false);
                        writer.Write(classResult.ToString());
                        writer.Close();

                        classResult.Clear();
                    }
                }
                StreamWriter writer2 = new StreamWriter(StaticData.InterfaceFileNameTemplate.Replace(StaticData.ServiceName, Properties.Settings.Default.ServiceName));
                writer2.Write(interfaceResult.ToString());
                writer2.Close();
                MessageBox.Show("Generate from service interface file", "Generating is completed.");
            }
        }
    }
}
